#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <conio.h>
#include <crtdbg.h>
#include <new> // for placement new
#include <ObjBase.h>

// Include Visual Leak Detector
#include "..\..\include\vld.h"

BOOL bFree = FALSE;
void Test_malloc();
void Test_new();
void Test_new_array();
void Test_calloc();
void Test_realloc();
void Test_CoTaskMem();
void Test_AlignedMalloc();
void Test_AlignedRealloc();
void Test_strdup();


int _tmain(int argc, _TCHAR* argv[])
{
	printf("Choose an exception type:\n");
	printf("0 - All type\n");
	printf("1 - malloc\n");
	printf("2 - new\n");
	printf("3 - new_array\n");
	printf("4 - calloc\n");
	printf("5 - realloc\n");	
	printf("6 - CoTaskMem\n");
	printf("7 - AlignedMalloc\n");
	printf("8 - AlignedRealloc\n");
	printf("9 - strdup\n");
	printf("Your choice >  ");

	int LeakType = 0;
	scanf_s("%d", &LeakType);

	printf("\nDo you want to free the memory (y/n)?\n");
	printf("Your choice >  ");
	getchar();
	char szAnswer[1024] = "";
#if _MSC_VER>=1400
	gets_s(szAnswer, 1024);  
#else
	gets(szAnswer);  
#endif

	if(strcmp(szAnswer, "y")==0 || 
		strcmp(szAnswer, "Y")==0)
		bFree = TRUE;

	switch(LeakType)
	{
	case 0: // All type
		Test_malloc();
		Test_new();
		Test_new_array();
		Test_calloc();
		Test_realloc();
		Test_CoTaskMem();
		Test_AlignedMalloc();
		Test_AlignedRealloc();
		Test_strdup();
		break;
	case 1: 
		Test_malloc();
		break;
	case 2: 
		Test_new();
		break;
	case 3: 
		Test_new_array();
		break;
	case 4: 
		Test_calloc();
		break;
	case 5: 
		Test_realloc();
		break;
	case 6: 
		Test_CoTaskMem();
		break;
	case 7: 
		Test_AlignedMalloc();
		break;
	case 8: 
		Test_AlignedRealloc();
		break;
	case 9: 
		Test_strdup();
		break;
	}
	_getch();
	return 0;
}

void Test_malloc()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;

	leaked_memory     = (int*)malloc(78);
	leaked_memory_dbg = (int*)_malloc_dbg(80, _NORMAL_BLOCK,__FILE__,__LINE__);
	if (bFree)
	{
		free(leaked_memory);
		_free_dbg(leaked_memory_dbg,_NORMAL_BLOCK);
	}
}

void Test_new()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	leaked_memory = new int(4);
	leaked_memory_dbg = new (_NORMAL_BLOCK, __FILE__, __LINE__) int(7);
	if (bFree)
	{
		delete leaked_memory;
		delete leaked_memory_dbg;
	}
}

void Test_new_array()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	leaked_memory = new int[3];
	leaked_memory_dbg = new (_NORMAL_BLOCK,__FILE__,__LINE__) int[4];

	// placement new operator
	int temp[3];
	void* place = temp;
	float* placed_mem = new (place) float[3]; // doesn't work. Nothing gets patched by vld
	if (bFree)
	{
		delete [] leaked_memory;
		delete [] leaked_memory_dbg;
	}
}

void Test_calloc()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	leaked_memory     = (int*)calloc(47,sizeof(int));
	leaked_memory_dbg = (int*)_calloc_dbg(39, sizeof(int), _NORMAL_BLOCK, __FILE__, __LINE__);
	if (bFree)
	{
		free(leaked_memory);
		_free_dbg(leaked_memory_dbg,_NORMAL_BLOCK);
	}
}

void Test_realloc()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	int* temp = (int*)malloc(17);
	leaked_memory = (int*)realloc(temp, 23);
	leaked_memory = (int*)_recalloc(leaked_memory, 1, 31);
	int* temp_dbg = (int*)malloc(9);
	leaked_memory_dbg = (int*)_realloc_dbg(temp_dbg, 21, _NORMAL_BLOCK, __FILE__, __LINE__);
	if (bFree)
	{
		free(leaked_memory);
		_free_dbg(leaked_memory_dbg,_NORMAL_BLOCK);
	}
}

void Test_CoTaskMem()
{
	void* leaked = CoTaskMemAlloc(7);
	void* realloced = CoTaskMemRealloc(leaked, 29);
	if (bFree)
	{
		CoTaskMemFree(realloced);
	}
}

void Test_AlignedMalloc()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	void* leaked = _aligned_offset_malloc(64, 16, 1);
	leaked_memory = (int*)_aligned_malloc(64, 16);
	leaked_memory_dbg = (int*)_aligned_malloc_dbg(32, 16, __FILE__, __LINE__);
	if (bFree)
	{
		_aligned_free(leaked);
		_aligned_free(leaked_memory);
		_aligned_free_dbg(leaked_memory_dbg);
	}
}
void Test_AlignedRealloc()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	void* leaked = _aligned_offset_malloc(64, 16, 1);
	leaked_memory = (int*)_aligned_malloc(64, 16);
	leaked_memory_dbg = (int*)_aligned_malloc_dbg(32, 16, __FILE__, __LINE__);
	leaked = (int*)_aligned_offset_realloc(leaked, 48, 16, 2);
	leaked_memory = (int*)_aligned_realloc(leaked_memory, 128, 16);
	leaked_memory_dbg = (int*)_aligned_realloc_dbg(leaked_memory_dbg, 48, 16, __FILE__, __LINE__);
	leaked = (int*)_aligned_offset_recalloc(leaked, 1, 52, 16, 2);
	leaked_memory = (int*)_aligned_recalloc(leaked_memory, 1, 132, 16);
	leaked_memory_dbg = (int*)_aligned_recalloc_dbg(leaked_memory_dbg, 1, 64, 16, __FILE__, __LINE__);
	if (bFree)
	{
		_aligned_free(leaked);
		_aligned_free(leaked_memory);
		_aligned_free_dbg(leaked_memory_dbg);
	}
}
void Test_strdup()
{
	int* leaked_memory = NULL;
	int* leaked_memory_dbg = NULL;
	leaked_memory     = (int*)_strdup("strdup() leaks!");
	leaked_memory_dbg = (int*)_strdup_dbg("_strdup_dbg() leaks!", _NORMAL_BLOCK,__FILE__,__LINE__);
	void* leaked_wmemory = (int*)_wcsdup(L"wcsdup() leaks!");
	void* leaked_wmemory_dbg = (int*)_wcsdup_dbg(L"_wcsdup_dbg() leaks!", _NORMAL_BLOCK,__FILE__,__LINE__);
	if (bFree)
	{
		free(leaked_memory);
		_free_dbg(leaked_memory_dbg,_NORMAL_BLOCK);
		free(leaked_wmemory);
		_free_dbg(leaked_wmemory_dbg,_NORMAL_BLOCK);
	}
}